home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / src / display.c < prev    next >
C/C++ Source or Header  |  1993-01-05  |  35KB  |  1,227 lines

  1. /*    SCCS Id: @(#)display.c    3.1    92/10/25    */
  2. /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */
  3. /* and Dave Cohrs, 1990.                      */
  4. /* NetHack may be freely redistributed.  See license for details. */
  5.  
  6. /*
  7.  *            THE NEW DISPLAY CODE
  8.  *
  9.  * The old display code has been broken up into three parts: vision, display,
  10.  * and drawing.  Vision decides what locations can and cannot be physically
  11.  * seen by the hero.  Display decides _what_ is displayed at a given location.
  12.  * Drawing decides _how_ to draw a monster, fountain, sword, etc.
  13.  *
  14.  * The display system uses information from the vision system to decide
  15.  * what to draw at a given location.  The routines for the vision system
  16.  * can be found in vision.c and vision.h.  The routines for display can
  17.  * be found in this file (display.c) and display.h.  The drawing routines
  18.  * are part of the window port.  See doc/window.doc for the drawing
  19.  * interface.
  20.  *
  21.  * The display system deals with an abstraction called a glyph.  Anything
  22.  * that could possibly be displayed has a unique glyph identifier.
  23.  *
  24.  * What is seen on the screen is a combination of what the hero remembers
  25.  * and what the hero currently sees.  Objects and dungeon features (walls
  26.  * doors, etc) are remembered when out of sight.  Monsters and temporary
  27.  * effects are not remembered.  Each location on the level has an
  28.  * associated glyph.  This is the hero's _memory_ of what he or she has
  29.  * seen there before.
  30.  *
  31.  * Display rules:
  32.  *
  33.  *    If the location is in sight, display in order:
  34.  *        visible monsters
  35.  *        visible objects
  36.  *        known traps
  37.  *        background
  38.  *
  39.  *    If the location is out of sight, display in order:
  40.  *        sensed monsters (telepathy)
  41.  *        memory
  42.  *
  43.  *
  44.  *
  45.  * Here is a list of the major routines in this file to be used externally:
  46.  *
  47.  * newsym
  48.  *
  49.  * Possibly update the screen location (x,y).  This is the workhorse routine.
  50.  * It is always correct --- where correct means following the in-sight/out-
  51.  * of-sight rules.  **Most of the code should use this routine.**  This
  52.  * routine updates the map and displays monsters.
  53.  *
  54.  *
  55.  * map_background
  56.  * map_object
  57.  * map_trap
  58.  * unmap_object
  59.  *
  60.  * If you absolutely must override the in-sight/out-of-sight rules, there
  61.  * are two possibilities.  First, you can mess with vision to force the
  62.  * location in sight then use newsym(), or you can  use the map_* routines.
  63.  * The first has not been tried [no need] and the second is used in the
  64.  * detect routines --- detect object, magic mapping, etc.  The map_*
  65.  * routines *change* what the hero remembers.  All changes made by these
  66.  * routines will be sticky --- they will survive screen redraws.  Do *not*
  67.  * use these for things that only temporarily change the screen.  These
  68.  * routines are also used directly by newsym().  unmap_object is used to
  69.  * clear a remembered object when/if detection reveals it isn't there.
  70.  *
  71.  *
  72.  * show_glyph
  73.  *
  74.  * This is direct (no processing in between) buffered access to the screen.
  75.  * Temporary screen effects are run through this and its companion,
  76.  * flush_screen().  There is yet a lower level routine, print_glyph(),
  77.  * but this is unbuffered and graphic dependent (i.e. it must be surrounded
  78.  * by graphic set-up and tear-down routines).  Do not use print_glyph().
  79.  *
  80.  *
  81.  * see_monsters
  82.  * see_objects
  83.  *
  84.  * These are only used when something affects all of the monsters or
  85.  * objects.  For objects, the only thing is hallucination.  For monsters,
  86.  * there are hallucination and changing from/to blindness, etc.
  87.  *
  88.  *
  89.  * tmp_at
  90.  *
  91.  * This is a useful interface for displaying temporary items on the screen.
  92.  * Its interface is different than previously, so look at it carefully.
  93.  *
  94.  *
  95.  *
  96.  * Parts of the rm structure that are used:
  97.  *
  98.  *    typ    - What is really there.
  99.  *    glyph    - What the hero remembers.  This will never be a monster.
  100.  *          Monsters "float" above this.
  101.  *    lit    - True if the position is lit.  An optimization for
  102.  *          lit/unlit rooms.
  103.  *    waslit    - True if the position was *remembered* as lit.
  104.  *    seen    - Set to true when the location is seen or felt as it really
  105.  *          is.  This is used primarily for walls, which look like stone
  106.  *          if seen from the outside of a room.  However, this is
  107.  *          also used as a guide for blind heros.  If the hero has
  108.  *          seen or felt a room feature underneath a boulder, when the
  109.  *          boulder is moved, the hero should see it again.  This is
  110.  *          also used as an indicator for unmapping detected objects.
  111.  *
  112.  *    doormask   - Additional information for the typ field.
  113.  *    horizontal - Indicates whether the wall or door is horizontal or
  114.  *             vertical.
  115.  */
  116. #include "hack.h"
  117.  
  118. static void FDECL(display_monster,(XCHAR_P,XCHAR_P,struct monst *,int,XCHAR_P));
  119. static int FDECL(swallow_to_glyph, (int, int));
  120.  
  121. #ifdef INVISIBLE_OBJECTS
  122. /*
  123.  * vobj_at()
  124.  *
  125.  * Returns a pointer to an object if the hero can see an object at the
  126.  * given location.  This takes care of invisible objects.  NOTE, this
  127.  * assumes that the hero is not blind and on top of the object pile.
  128.  * It does NOT take into account that the location is out of sight, or,
  129.  * say, one can see blessed, etc.
  130.  */
  131. struct obj *
  132. vobj_at(x,y)
  133.     xchar x,y;
  134. {
  135.     register struct obj *obj = level.objects[x][y];
  136.  
  137.     while (obj) {
  138.     if (!obj->oinvis || See_invisible) return obj;
  139.     obj = obj->nexthere;
  140.     }
  141.     return ((struct obj *) 0);
  142. }
  143. #endif    /* else vobj_at() is defined in display.h */
  144.  
  145. /*
  146.  * The routines map_background(), map_object(), and map_trap() could just
  147.  * as easily be:
  148.  *
  149.  *    map_glyph(x,y,glyph,show)
  150.  *
  151.  * Which is called with the xx_to_glyph() in the call.  Then I can get
  152.  * rid of 3 routines that don't do very much anyway.  And then stop
  153.  * having to create fake objects and traps.  However, I am reluctant to
  154.  * make this change.
  155.  */
  156.  
  157. /*
  158.  * map_background()
  159.  *
  160.  * Make the real background part of our map.  This routine assumes that
  161.  * the hero can physically see the location.  Update the screen if directed.
  162.  */
  163. void
  164. map_background(x, y, show)
  165.     register xchar x,y;
  166.     register int  show;
  167. {
  168.     register int glyph = back_to_glyph(x,y);
  169.  
  170.     if (level.flags.hero_memory)
  171.     levl[x][y].glyph = glyph;
  172.     if (show) show_glyph(x,y, glyph);
  173. }
  174.  
  175. /*
  176.  * map_trap()
  177.  *
  178.  * Map the trap and print it out if directed.  This routine assumes that the
  179.  * hero can physically see the location.
  180.  */
  181. void
  182. map_trap(trap, show)
  183.     register struct trap *trap;
  184.     register int     show;
  185. {
  186.     register int x = trap->tx, y = trap->ty;
  187.     register int glyph = trap_to_glyph(trap);
  188.  
  189.     if (level.flags.hero_memory)
  190.     levl[x][y].glyph = glyph;
  191.     if (show) show_glyph(x, y, glyph);
  192. }
  193.  
  194. /*
  195.  * map_object()
  196.  *
  197.  * Map the given object.  This routine assumes that the hero can physically
  198.  * see the location of the object.  Update the screen if directed.
  199.  */
  200. void
  201. map_object(obj, show)
  202.     register struct obj *obj;
  203.     register int    show;
  204. {
  205.     register int x = obj->ox, y = obj->oy;
  206.     register int glyph = obj_to_glyph(obj);
  207.  
  208.     if (level.flags.hero_memory)
  209.     levl[x][y].glyph = glyph;
  210.     if (show) show_glyph(x, y, glyph);
  211. }
  212.  
  213. /*
  214.  * unmap_object()
  215.  *
  216.  * Remove something from the map when detection reveals that it isn't
  217.  * there any more.  Replace it with background or known trap, but not
  218.  * with any other remembered object.  No need to update the display;
  219.  * a full update is imminent.
  220.  *
  221.  * This isn't quite correct due to overloading of the seen bit.  But
  222.  * it works well enough for now.
  223.  */
  224. void
  225. unmap_object(x, y)
  226.     register int x, y;
  227. {
  228.     register struct trap *trap;
  229.  
  230.     if (!level.flags.hero_memory) return;
  231.  
  232.     if ((trap = t_at(x,y)) != 0 && trap->tseen && !covers_traps(x,y))
  233.     map_trap(trap, 0);
  234.     else if (levl[x][y].seen) {
  235.     struct rm *lev = &levl[x][y];
  236.  
  237.     map_background(x, y, 0);
  238.  
  239.     /* turn remembered dark room squares dark */
  240.     if (!lev->waslit && lev->glyph == cmap_to_glyph(S_room) &&
  241.                                 lev->typ == ROOM)
  242.         lev->glyph = cmap_to_glyph(S_stone);
  243.     } else 
  244.     levl[x][y].glyph = cmap_to_glyph(S_stone);    /* default val */
  245. }
  246.  
  247.  
  248. /*
  249.  * map_location()
  250.  *
  251.  * Make whatever at this location show up.  This is only for non-living
  252.  * things.  This will not handle feeling invisible objects correctly.
  253.  */
  254. #define map_location(x,y,show)                        \
  255. {                                    \
  256.     register struct obj   *obj;                        \
  257.     register struct trap  *trap;                    \
  258.                                     \
  259.     if ((obj = vobj_at(x,y)) && !covers_objects(x,y))            \
  260.     map_object(obj,show);                        \
  261.     else if ((trap = t_at(x,y)) && trap->tseen && !covers_traps(x,y))    \
  262.     map_trap(trap,show);                        \
  263.     else                                \
  264.     map_background(x,y,show);                    \
  265. }
  266.  
  267.  
  268. /*
  269.  * display_monster()
  270.  *
  271.  * Note that this is *not* a map_XXXX() function!  Monsters sort of float
  272.  * above everything.
  273.  *
  274.  * Yuck.  Display body parts by recognizing that the display position is
  275.  * not the same as the monster position.  Currently the only body part is
  276.  * a worm tail.
  277.  *  
  278.  */
  279. static void
  280. display_monster(x, y, mon, in_sight, worm_tail)
  281.     register xchar x, y;    /* display position */
  282.     register struct monst *mon;    /* monster to display */
  283.     int in_sight;        /* TRUE if the monster is physically seen */
  284.     register xchar worm_tail;    /* mon is actually a worm tail */
  285. {
  286.     register boolean mon_mimic = (mon->m_ap_type != M_AP_NOTHING);
  287.     register int sensed = mon_mimic &&
  288.     (Protection_from_shape_changers || sensemon(mon));
  289.  
  290.     /*
  291.      * We must do the mimic check first.  If the mimic is mimicing something,
  292.      * and the location is in sight, we have to change the hero's memory
  293.      * so that when the position is out of sight, the hero remembers what
  294.      * the mimic was mimicing.
  295.      */
  296.  
  297.     if (mon_mimic && in_sight) {
  298.     switch (mon->m_ap_type) {
  299.         default:
  300.         impossible("display_monster:  bad m_ap_type value [ = %d ]",
  301.                             (int) mon->m_ap_type);
  302.         case M_AP_NOTHING:
  303.         show_glyph(x, y, mon_to_glyph(mon));
  304.         break;
  305.  
  306.         case M_AP_FURNITURE: {
  307.         /*
  308.          * This is a poor man's version of map_background().  I can't
  309.          * use map_background() because we are overriding what is in
  310.          * the 'typ' field.  Maybe have map_background()'s parameters
  311.          * be (x,y,glyph) instead of just (x,y).
  312.          *
  313.          * mappearance is currently set to an S_ index value in
  314.          * makemon.c.
  315.          */
  316.         register int glyph = cmap_to_glyph(mon->mappearance);
  317.         levl[x][y].glyph = glyph;
  318.         if (!sensed) show_glyph(x,y, glyph);
  319.         break;
  320.         }
  321.  
  322.         case M_AP_OBJECT: {
  323.         struct obj obj;    /* Make a fake object to send    */
  324.                 /* to map_object().        */
  325.         obj.ox = x;
  326.         obj.oy = y;
  327.         obj.otyp = mon->mappearance;
  328.         obj.corpsenm = PM_TENGU;    /* if mimicing a corpse */
  329.         map_object(&obj,!sensed);
  330.         break;
  331.         }
  332.  
  333.         case M_AP_MONSTER:
  334.         show_glyph(x,y, monnum_to_glyph(what_mon(mon->mappearance)));
  335.         break;
  336.     }
  337.     
  338.     }
  339.  
  340.     /* If the mimic is unsucessfully mimicing something, display the monster */
  341.     if (!mon_mimic || sensed) {
  342.     if (mon->mtame) {
  343.         if (worm_tail)
  344.         show_glyph(x,y, petnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)));
  345.         else    
  346.         show_glyph(x,y, pet_to_glyph(mon));
  347.     } else {
  348.         if (worm_tail)
  349.         show_glyph(x,y, monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)));
  350.         else    
  351.         show_glyph(x,y, mon_to_glyph(mon));
  352.     }
  353.     }
  354. }
  355.  
  356. /*
  357.  * feel_location()
  358.  *
  359.  * Feel the given location.  This assumes that the hero is blind and that
  360.  * the given position is either the hero's or one of the eight squares
  361.  * adjacent to the hero (except for a boulder push).
  362.  */
  363. void
  364. feel_location(x, y)
  365.     xchar x, y;
  366. {
  367.     struct rm *lev = &(levl[x][y]);
  368.     struct obj *boulder;
  369.     register struct monst *mon;
  370.  
  371.     /* The hero can't feel non pool locations while under water. */
  372.     if (Underwater && !Is_waterlevel(&u.uz) && ! is_pool(x,y))
  373.     return;
  374.  
  375.     /* If the hero is not in a corridor, then she will feel the wall as a */
  376.     /* wall.  It doesn't matter if the hero is levitating or not.      */
  377.     if ((IS_WALL(lev->typ) || lev->typ == SDOOR) &&
  378.                         levl[u.ux][u.uy].typ != CORR)
  379.     lev->seen = 1;
  380.  
  381.     if (Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) {
  382.     /*
  383.      * Levitation Rules.  It is assumed that the hero can feel the state
  384.      * of the walls around herself and can tell if she is in a corridor,
  385.      * room, or doorway.  Boulders are felt because they are large enough.
  386.      * Anything else is unknown because the hero can't reach the ground.
  387.      * This makes things difficult.
  388.      *
  389.      * Check (and display) in order:
  390.      *
  391.      *    + Stone, walls, and closed doors.
  392.      *    + Boulders.  [see a boulder before a doorway]
  393.      *    + Doors.
  394.      *    + Room/water positions
  395.      *    + Everything else (hallways!)
  396.      */
  397.     if (IS_ROCK(lev->typ) || (IS_DOOR(lev->typ) &&
  398.                 (lev->doormask & (D_LOCKED | D_CLOSED)))) {
  399.         map_background(x, y, 1);
  400.     } else if (boulder = sobj_at(BOULDER,x,y)) {
  401.         map_object(boulder, 1);
  402.     } else if (IS_DOOR(lev->typ)) {
  403.         map_background(x, y, 1);
  404.     } else if (IS_ROOM(lev->typ) || IS_POOL(lev->typ)) {
  405.         /*
  406.          * An open room or water location.  Normally we wouldn't touch
  407.          * this, but we have to get rid of remembered boulder symbols.
  408.          * This will only occur in rare occations when the hero goes
  409.          * blind and doesn't find a boulder where expected (something
  410.          * came along and picked it up).  We know that there is not a
  411.          * boulder at this location.  Show fountains, pools, etc.
  412.          * underneath if already seen.  Otherwise, show the appropriate
  413.          * floor symbol.
  414.          *
  415.          * This isn't quite correct.  If the boulder was on top of some
  416.          * other objects they should be seen once the boulder is removed.
  417.          * However, we have no way of knowing that what is there now
  418.          * was there then.  So we let the hero have a lapse of memory.
  419.          * We could also just display what is currently on the top of the
  420.          * object stack (if anything).
  421.          */
  422.         if (lev->glyph == objnum_to_glyph(BOULDER)) {
  423.         if (lev->typ != ROOM && lev->seen) {
  424.             map_background(x, y, 1);
  425.         } else {
  426.             lev->glyph = lev->waslit ? cmap_to_glyph(S_room) :
  427.                            cmap_to_glyph(S_stone);
  428.             show_glyph(x,y,lev->glyph);
  429.         }
  430.         }
  431.     } else {
  432.         /* We feel it (I think hallways are the only things left). */
  433.         map_background(x, y, 1);
  434.         /* Corridors are never felt as lit (unless remembered that way) */
  435.         /* (lit_corridor only).                        */
  436.         if (lev->typ == CORR &&
  437.             lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit)
  438.         show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
  439.     }
  440.     } else {
  441.     map_location(x, y, 1);
  442.  
  443.     if (Punished) {
  444.         /*
  445.          * A ball or chain is only felt if it is first on the object
  446.          * location list.  Otherwise, we need to clear the felt bit ---
  447.          * something has been dropped on the ball/chain.  If the bit is
  448.          * not cleared, then when the ball/chain is moved it will drop
  449.          * the wrong glyph.
  450.          */
  451.         if (uchain->ox == x && uchain->oy == y) {
  452.         if (level.objects[x][y] == uchain)
  453.             u.bc_felt |= BC_CHAIN;
  454.         else
  455.             u.bc_felt &= ~BC_CHAIN;    /* do not feel the chain */
  456.         }
  457.         if (!carried(uball) && uball->ox == x && uball->oy == y) {
  458.         if (level.objects[x][y] == uball)
  459.             u.bc_felt |= BC_BALL;
  460.         else
  461.             u.bc_felt &= ~BC_BALL;    /* do not feel the ball */
  462.         }
  463.     }
  464.  
  465.     /* Floor spaces are dark if unlit.  Corridors are dark if unlit. */
  466.     if (lev->typ == ROOM &&
  467.             lev->glyph == cmap_to_glyph(S_room) && !lev->waslit)
  468.         show_glyph(x,y, lev->glyph = cmap_to_glyph(S_stone));
  469.     else if (lev->typ == CORR &&
  470.             lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit)
  471.         show_glyph(x,y, lev->glyph = cmap_to_glyph(S_corr));
  472.     }
  473.     /* draw monster on top if we can sense it */
  474.     if ((x != u.ux || y != u.uy) && (mon = m_at(x,y)) && sensemon(mon))
  475.     display_monster(x,y,mon,1,((x != mon->mx)  || (y != mon->my)));
  476. }
  477.  
  478. /*
  479.  * newsym()
  480.  *
  481.  * Possibly put a new glyph at the given location.
  482.  */
  483. void
  484. newsym(x,y)
  485.     register xchar x,y;
  486. {
  487.     register struct monst *mon;
  488.     register struct rm *lev = &(levl[x][y]);
  489.     register int see_it;
  490.     register xchar worm_tail;
  491.  
  492.     /* only permit updating the hero when swallowed */
  493.     if (u.uswallow) {
  494.     if (x == u.ux && y == u.uy) display_self();
  495.     return;
  496.     }
  497.     if (Underwater && !Is_waterlevel(&u.uz)) {
  498.     /* don't do anything unless (x,y) is an adjacent underwater position */
  499.     int dx, dy;
  500.     if (!is_pool(x,y)) return;
  501.     dx = x - u.ux;    if (dx < 0) dx = -dx;
  502.     dy = y - u.uy;    if (dy < 0) dy = -dy;
  503.     if (dx > 1 || dy > 1) return;
  504.     }
  505.  
  506.     /* Can physically see the location. */
  507.     if (cansee(x,y)) {
  508.     lev->waslit = (lev->lit!=0);    /* remember lit condition */
  509.  
  510.     if (x == u.ux && y == u.uy) {
  511.         if (canseeself()) {
  512.         map_location(x,y,0);    /* map *under* self */
  513.         display_self();
  514.         } else
  515.         /* we can see what is there */
  516.         map_location(x,y,1);
  517.     }
  518.     else if ((mon = m_at(x,y)) &&
  519.          ((see_it = mon_visible(mon)) || sensemon(mon))) {
  520.         map_location(x,y,0);     /* map under the monster */
  521.             worm_tail = ((x != mon->mx)  || (y != mon->my));
  522.         display_monster(x,y,mon,see_it,worm_tail);
  523.     }
  524.     else
  525.         map_location(x,y,1);    /* map the location */
  526.     }
  527.  
  528.     /* Can't see the location. */
  529.     else {
  530.     if (x == u.ux && y == u.uy) {
  531.         feel_location(u.ux, u.uy);        /* forces an update */
  532.  
  533.         if (canseeself()) display_self();
  534.     }
  535.     else if ((mon = m_at(x,y)) && sensemon(mon) &&
  536.                      !((x != mon->mx)  || (y != mon->my))) {
  537.         /* Monsters are printed every time. */
  538.         display_monster(x,y,mon,0,0);
  539.     }
  540.     /*
  541.      * If the location is remembered as being both dark (waslit is false)
  542.      * and lit (glyph is a lit room or lit corridor) then it was either:
  543.      *
  544.      *    (1) A dark location that the hero could see through night
  545.      *        vision.
  546.      *
  547.      *    (2) Darkened while out of the hero's sight.  This can happen
  548.      *        when cursed scroll of light is read.
  549.      *
  550.      * In either case, we have to manually correct the hero's memory to
  551.      * match waslit.  Deciding when to change waslit is non-trivial.
  552.      *
  553.      *  Note:  If flags.lit_corridor is set, then corridors act like room
  554.      *       squares.  That is, they light up if in night vision range.
  555.      *       If flags.lit_corridor is not set, then corridors will
  556.      *       remain dark unless lit by a light spell.
  557.      *
  558.      * These checks and changes must be here and not in back_to_glyph().
  559.      * They are dependent on the position being out of sight.
  560.      */
  561.     else if (!lev->waslit) {
  562.         if (flags.lit_corridor && lev->glyph == cmap_to_glyph(S_litcorr) &&
  563.                                 lev->typ == CORR)
  564.         show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr));
  565.         else if (lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM)
  566.         show_glyph(x, y, lev->glyph = cmap_to_glyph(S_stone));
  567.         else
  568.         goto show_mem;
  569.     } else {
  570. show_mem:
  571.         show_glyph(x, y, lev->glyph);
  572.     }
  573.     }
  574. }
  575.  
  576.  
  577. /*
  578.  * shieldeff()
  579.  *
  580.  * Put magic shield pyrotechnics at the given location.  This *could* be
  581.  * pulled into a platform dependent routine for fancier graphics if desired.
  582.  */
  583. void
  584. shieldeff(x,y)
  585.     xchar x,y;
  586. {
  587.     register int i;
  588.  
  589.     if (cansee(x,y)) {    /* Don't see anything if can't see the location */
  590.     for (i = 0; i < SHIELD_COUNT; i++) {
  591.         show_glyph(x, y, cmap_to_glyph(shield_static[i]));
  592.         flush_screen(1);    /* make sure the glyph shows up */
  593.         delay_output();
  594.     }
  595.     newsym(x,y);        /* restore the old information */
  596.     }
  597. }
  598.  
  599.  
  600. /*
  601.  * tmp_at()
  602.  *
  603.  * Temporarily place glyphs on the screen.  Do not call delay_output().  It
  604.  * is up to the caller to decide if it wants to wait [presently, everyone
  605.  * but explode() wants to delay].
  606.  *
  607.  * Call:
  608.  *    (DISP_BEAM,   glyph)    open, initialize glyph
  609.  *    (DISP_FLASH,  glyph)    open, initialize glyph
  610.  *    (DISP_CHANGE, glyph)    change glyph
  611.  *    (DISP_END,    0)    close & clean up (second argument doesn't
  612.  *                matter)
  613.  *    (x, y)            display the glyph at the location
  614.  *
  615.  * DISP_BEAM  - Display the given glyph at each location, but do not erase
  616.  *        any until the close call.
  617.  * DISP_FLASH - Display the given glyph at each location, but erase the
  618.  *        previous location's glyph.
  619.  */
  620. void
  621. tmp_at(x, y)
  622.     int x, y;
  623. {
  624.     static coord saved[COLNO];    /* prev positions, only for DISP_BEAM */
  625.     static int sidx = 0;    /* index of saved previous positions */
  626.     static int sx = -1, sy;    /* previous position, only for DISP_FLASH */
  627.     static int status;        /* either DISP_BEAM or DISP_FLASH */
  628.     static int glyph;        /* glyph to use when printing */
  629.  
  630.     switch (x) {
  631.     case DISP_BEAM:
  632.     case DISP_FLASH:
  633.         status = x;
  634.         glyph  = y;
  635.         flush_screen(0);    /* flush buffered glyphs */
  636.         break;
  637.  
  638.     case DISP_CHANGE:
  639.         glyph = y;
  640.         break;
  641.  
  642.     case DISP_END:
  643.         if (status == DISP_BEAM) {
  644.         register int i;
  645.  
  646.         /* Erase (reset) from source to end */
  647.         for (i = 0; i < sidx; i++)
  648.             newsym(saved[i].x,saved[i].y);
  649.         sidx = 0;
  650.         
  651.         } else if (sx >= 0) {    /* DISP_FLASH (called at least once) */
  652.         newsym(sx,sy);    /* reset the location */
  653.         sx = -1;    /* reset sx to an illegal pos for next time */
  654.         }
  655.         break;
  656.  
  657.     default:    /* do it */
  658.         if (!cansee(x,y)) break;
  659.  
  660.         if (status == DISP_BEAM) {
  661.         saved[sidx  ].x = x;    /* save pos for later erasing */
  662.         saved[sidx++].y = y;
  663.         }
  664.  
  665.         else {    /* DISP_FLASH */
  666.         if (sx >= 0)        /* not first call */
  667.             newsym(sx,sy);    /* update the old position */
  668.  
  669.         sx = x;        /* save previous pos for next call */
  670.         sy = y;
  671.         }
  672.  
  673.         show_glyph(x,y,glyph);    /* show it */
  674.         flush_screen(0);        /* make sure it shows up */
  675.         break;
  676.     } /* end case */
  677. }
  678.  
  679.  
  680. /*
  681.  * swallowed()
  682.  *
  683.  * The hero is swallowed.  Show a special graphics sequence for this.  This
  684.  * bypasses all of the display routines and messes with buffered screen
  685.  * directly.  This method works because both vision and display check for
  686.  * being swallowed.
  687.  */
  688. void
  689. swallowed(first)
  690.     int first;
  691. {
  692.     static xchar lastx, lasty;    /* last swallowed position */
  693.     int swallower;
  694.  
  695.     if (first)
  696.     cls();
  697.     else {
  698.     register int x, y;
  699.  
  700.     /* Clear old location */
  701.     for (y = lasty-1; y <= lasty+1; y++)
  702.         if(isok(lastx,y)) {
  703.         for (x = lastx-1; x <= lastx+1; x++)
  704.             show_glyph(x,y,cmap_to_glyph(S_stone));
  705.         }
  706.     }
  707.  
  708.     swallower = monsndx(u.ustuck->data);
  709.     /*
  710.      *  Display the hero surrounded by the monster's stomach.
  711.      */
  712.     if(isok(u.ux, u.uy-1)) {
  713.     show_glyph(u.ux-1, u.uy-1, swallow_to_glyph(swallower, S_sw_tl));
  714.     show_glyph(u.ux  , u.uy-1, swallow_to_glyph(swallower, S_sw_tc));
  715.     show_glyph(u.ux+1, u.uy-1, swallow_to_glyph(swallower, S_sw_tr));
  716.     }
  717.  
  718.     show_glyph(u.ux-1, u.uy  , swallow_to_glyph(swallower, S_sw_ml));
  719.     display_self();
  720.     show_glyph(u.ux+1, u.uy  , swallow_to_glyph(swallower, S_sw_mr));
  721.  
  722.     if(isok(u.ux, u.uy+1)) {
  723.     show_glyph(u.ux-1, u.uy+1, swallow_to_glyph(swallower, S_sw_bl));
  724.     show_glyph(u.ux  , u.uy+1, swallow_to_glyph(swallower, S_sw_bc));
  725.     show_glyph(u.ux+1, u.uy+1, swallow_to_glyph(swallower, S_sw_br));
  726.     }
  727.  
  728.     /* Update the swallowed position. */
  729.     lastx = u.ux;
  730.     lasty = u.uy;
  731. }
  732.  
  733. /*
  734.  * under_water()
  735.  *
  736.  * Similar to swallowed() in operation.  Shows hero when underwater
  737.  * except when in water level.  Special routines exist for that.
  738.  */
  739. void
  740. under_water(mode)
  741.     int mode;
  742. {
  743.     static xchar lastx, lasty;
  744.     static boolean dela;
  745.     register int x, y;
  746.  
  747.     /* swallowing has a higher precedence than under water */
  748.     if (Is_waterlevel(&u.uz) || u.uswallow) return;
  749.  
  750.     /* full update */
  751.     if (mode == 1 || dela) {
  752.     cls();
  753.     dela = FALSE;
  754.     }   
  755.     /* delayed full update */
  756.     else if (mode == 2) {
  757.     dela = TRUE;
  758.     return;
  759.     }
  760.     /* limited update */
  761.     else {
  762.     for (y = lasty-1; y <= lasty+1; y++)
  763.         for (x = lastx-1; x <= lastx+1; x++)
  764.         if (isok(x,y)) 
  765.             show_glyph(x,y,cmap_to_glyph(S_stone));
  766.     }
  767.     for (x = u.ux-1; x <= u.ux+1; x++)
  768.     for (y = u.uy-1; y <= u.uy+1; y++)
  769.         if (isok(x,y) && is_pool(x,y)) {
  770.         if (Blind && !(x == u.ux && y == u.uy))
  771.             show_glyph(x,y,cmap_to_glyph(S_stone));
  772.         else    
  773.             newsym(x,y);
  774.         }
  775.     lastx = u.ux;
  776.     lasty = u.uy;
  777. }
  778.  
  779.  
  780. /* ========================================================================= */
  781.  
  782. /*
  783.  * Loop through all of the monsters and update them.  Called when:
  784.  *    + going blind & telepathic
  785.  *    + regaining sight & telepathic
  786.  *    + hallucinating
  787.  *    + doing a full screen redraw
  788.  *    + see invisible times out or a ring of see invisible is taken off
  789.  *    + when a potion of see invisible is quaffed or a ring of see
  790.  *      invisible is put on
  791.  *    + gaining telepathy when blind [givit() in eat.c, pleased() in pray.c]
  792.  *    + losing telepathy while blind [xkilled() in mon.c, attrcurse() in
  793.  *      sit.c]
  794.  */
  795. void
  796. see_monsters()
  797. {
  798.     register struct monst *mon;
  799.     for (mon = fmon; mon; mon = mon->nmon) {
  800.     newsym(mon->mx,mon->my);
  801.     if (mon->wormno) see_wsegs(mon);
  802.     }
  803. }
  804.  
  805. /*
  806.  * Block/unblock light depending on what a mimic is mimicing and if it's
  807.  * invisible or not.  Should be called only when the state of See_invisible
  808.  * changes.
  809.  */
  810. void
  811. set_mimic_blocking()
  812. {
  813.     register struct monst *mon;
  814.     for (mon = fmon; mon; mon = mon->nmon)
  815.     if(mon->minvis &&
  816.        ((mon->m_ap_type == M_AP_FURNITURE &&
  817.           (mon->mappearance == S_vcdoor || mon->mappearance == S_hcdoor))||
  818.         (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER))) {
  819.         if(See_invisible)
  820.         block_point(mon->mx, mon->my);
  821.         else
  822.         unblock_point(mon->mx, mon->my);
  823.     }
  824. }
  825.  
  826. /*
  827.  * Loop through all of the object *locations* and update them.  Called when
  828.  *    + hallucinating.
  829.  */
  830. void
  831. see_objects()
  832. {
  833.     register struct obj *obj;
  834.     for(obj = fobj; obj; obj = obj->nobj)
  835.     if (vobj_at(obj->ox,obj->oy) == obj) newsym(obj->ox, obj->oy);
  836. }
  837.  
  838. /*
  839.  * Put the cursor on the hero.  Flush all accumulated glyphs before doing it.
  840.  */
  841. void
  842. curs_on_u()
  843. {
  844.     flush_screen(1);    /* Flush waiting glyphs & put cursor on hero */
  845. }
  846.  
  847. int
  848. doredraw()
  849. {
  850.     docrt();
  851.     return 0;
  852. }
  853.  
  854. void
  855. docrt()
  856. {
  857.     register int x,y;
  858.     register struct rm *lev;
  859.  
  860.     if (!u.ux) return; /* display isn't ready yet */
  861.  
  862.     if (u.uswallow) {
  863.     swallowed(1);
  864.     return;
  865.     }
  866.     if (Underwater && !Is_waterlevel(&u.uz)) {
  867.     under_water(1);
  868.     return;
  869.     }
  870.  
  871.     /* shut down vision */
  872.     vision_recalc(2);
  873.  
  874.     /*
  875.      * This routine assumes that cls() does the following:
  876.      *      + fills the physical screen with the symbol for rock
  877.      *      + clears the glyph buffer
  878.      */
  879.     cls();
  880.  
  881.     /* display memory */
  882.     for (x = 1; x < COLNO; x++) {
  883.     lev = &levl[x][0];
  884.     for (y = 0; y < ROWNO; y++, lev++)
  885.         if (lev->glyph != cmap_to_glyph(S_stone))
  886.         show_glyph(x,y,lev->glyph);
  887.     }
  888.  
  889.     /* see what is to be seen */
  890.     vision_recalc(0);
  891.  
  892.     /* overlay with monsters */
  893.     see_monsters();
  894.  
  895.     flags.botlx = 1;    /* force a redraw of the bottom line */
  896. }
  897.  
  898.  
  899. /* ========================================================================= */
  900. /* Glyph Buffering (3rd screen) ============================================ */
  901.  
  902. typedef struct {
  903.     xchar new;        /* perhaps move this bit into the rm strucure. */
  904.     int   glyph;
  905. } gbuf_entry;
  906.  
  907. static gbuf_entry gbuf[ROWNO][COLNO];
  908. static char gbuf_start[ROWNO];
  909. static char gbuf_stop[ROWNO];
  910.  
  911. /*
  912.  * Store the glyph in the 3rd screen for later flushing.
  913.  */
  914. void
  915. show_glyph(x,y,glyph)
  916.     xchar x,y;
  917.     int   glyph;
  918. {
  919.     /*
  920.      * Check for bad positions and glyphs.
  921.      */
  922.     if (x <= 0 || x >= COLNO || y < 0 || y >= ROWNO) {
  923.     const char *text;
  924.     int  offset;
  925.  
  926.     /* column 0 is invalid, but it's often used as a flag, so ignore it */
  927.     if (x == 0) return;
  928.  
  929.     /*
  930.      *  This assumes an ordering of the offsets.  See display.h for
  931.      *  the definition.
  932.      */
  933.     if (glyph >= GLYPH_SWALLOW_OFF) {        /* swallow border */
  934.         text = "swallow border";    offset = glyph - GLYPH_SWALLOW_OFF;
  935.     }else if (glyph >= GLYPH_ZAP_OFF) {        /* zap beam */
  936.         text = "zap beam";        offset = glyph - GLYPH_ZAP_OFF;
  937.     } else if (glyph >= GLYPH_CMAP_OFF) {        /* cmap */
  938.         text = "cmap_index";    offset = glyph - GLYPH_CMAP_OFF;
  939.     } else if (glyph >= GLYPH_TRAP_OFF) {        /* trap */
  940.         text = "trap";        offset = glyph - GLYPH_TRAP_OFF;
  941.     } else if (glyph >= GLYPH_OBJ_OFF) {        /* object */
  942.         text = "object";        offset = glyph - GLYPH_OBJ_OFF;
  943.     } else if (glyph >= GLYPH_BODY_OFF) {        /* a corpse */
  944.         text = "corpse";        offset = glyph - GLYPH_BODY_OFF;
  945.     } else {                    /* a monster */
  946.         text = "monster";        offset = glyph;
  947.     }
  948.  
  949.     impossible("show_glyph:  bad pos %d %d with glyph %d [%s %d].",
  950.                         x, y, glyph, text, offset);
  951.     return;
  952.     }
  953.  
  954.     if (glyph >= MAX_GLYPH) {
  955.     impossible("show_glyph:  bad glyph %d [max %d] at (%d,%d).",
  956.                     glyph, MAX_GLYPH, x, y);
  957.     return;
  958.     }
  959.  
  960.     if (gbuf[y][x].glyph != glyph) {
  961.     gbuf[y][x].glyph = glyph;
  962.     gbuf[y][x].new   = 1;
  963.     if (gbuf_start[y] > x) gbuf_start[y] = x;
  964.     if (gbuf_stop[y]  < x) gbuf_stop[y]  = x;
  965.     }
  966. }
  967.  
  968.  
  969. /*
  970.  * Reset the changed glyph borders so that none of the 3rd screen has
  971.  * changed.
  972.  */
  973. #define reset_glyph_bbox()            \
  974.     {                        \
  975.     int i;                    \
  976.                         \
  977.     for (i = 0; i < ROWNO; i++) {        \
  978.         gbuf_start[i] = COLNO-1;        \
  979.         gbuf_stop[i]  = 0;            \
  980.     }                    \
  981.     }
  982.  
  983.  
  984. static gbuf_entry nul_gbuf = { 0, cmap_to_glyph(S_stone) };
  985. /*
  986.  * Turn the 3rd screen into stone.
  987.  */
  988. void
  989. clear_glyph_buffer()
  990. {
  991.     register int x, y;
  992.     register gbuf_entry *gptr;
  993.  
  994.     for (y = 0; y < ROWNO; y++) {
  995.     gptr = &gbuf[y][0];
  996.     for (x = COLNO; x; x--) {
  997.         *gptr++ = nul_gbuf;
  998.     }
  999.     }
  1000.     reset_glyph_bbox();
  1001. }
  1002.  
  1003. /*
  1004.  * Assumes that the indicated positions are filled with S_stone glyphs.
  1005.  */
  1006. void
  1007. row_refresh(start,stop,y)
  1008.     int start,stop,y;
  1009. {
  1010.     register int x;
  1011.  
  1012.     for (x = start; x <= stop; x++)
  1013.     if (gbuf[y][x].glyph != cmap_to_glyph(S_stone))
  1014.         print_glyph(WIN_MAP,x,y,gbuf[y][x].glyph);
  1015. }
  1016.  
  1017. void
  1018. cls()
  1019. {
  1020.     display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */
  1021.     flags.botlx = 1;        /* force update of botl window */
  1022.     clear_nhwindow(WIN_MAP);    /* clear physical screen */
  1023.  
  1024.     clear_glyph_buffer();    /* this is sort of an extra effort, but OK */
  1025. }
  1026.  
  1027. /*
  1028.  * Synch the third screen with the display.
  1029.  */
  1030. void
  1031. flush_screen(cursor_on_u)
  1032.     int cursor_on_u;
  1033. {
  1034.     /* Prevent infinite loops on errors:
  1035.      *        flush_screen->print_glyph->impossible->pline->flush_screen
  1036.      */
  1037.     static   boolean flushing = 0;
  1038.     register int x,y;
  1039.  
  1040.     if (flushing) return;    /* if already flushing then return */
  1041.     flushing = 1;
  1042.  
  1043.     for (y = 0; y < ROWNO; y++) {
  1044.     register gbuf_entry *gptr = &gbuf[y][x = gbuf_start[y]];
  1045.     for (; x <= gbuf_stop[y]; gptr++, x++)
  1046.         if (gptr->new) {
  1047.         print_glyph(WIN_MAP,x,y,gptr->glyph);
  1048.         gptr->new = 0;
  1049.         }
  1050.     }
  1051.  
  1052.     if (cursor_on_u) curs(WIN_MAP, u.ux,u.uy); /* move cursor to the hero */
  1053.     display_nhwindow(WIN_MAP, FALSE);
  1054.     reset_glyph_bbox();
  1055.     flushing = 0;
  1056.     if(flags.botl || flags.botlx) bot();
  1057. }
  1058.  
  1059. /* ========================================================================= */
  1060.  
  1061. /*
  1062.  * back_to_glyph()
  1063.  *
  1064.  * Use the information in the rm structure at the given position to create
  1065.  * a glyph of a background.
  1066.  *
  1067.  * I had to add a field in the rm structure (horizontal) so that we knew
  1068.  * if open doors and secret doors were horizontal or vertical.  Previously,
  1069.  * the screen symbol had the horizontal/vertical information set at
  1070.  * level generation time.
  1071.  *
  1072.  * I used the 'ladder' field (really doormask) for deciding if stairwells
  1073.  * were up or down.  I didn't want to check the upstairs and dnstairs
  1074.  * variables.
  1075.  */
  1076. int
  1077. back_to_glyph(x,y)
  1078.     xchar x,y;
  1079. {
  1080.     int idx;
  1081.     struct rm *ptr = &(levl[x][y]);
  1082.  
  1083.     switch (ptr->typ) {
  1084.     case SCORR:
  1085.     case STONE:        idx = S_stone;      break;
  1086.     case ROOM:        idx = S_room;      break;
  1087.     case CORR:
  1088.         idx = (ptr->waslit || flags.lit_corridor) ? S_litcorr : S_corr;
  1089.         break;
  1090.     case HWALL:    idx = ptr->seen ? S_hwall  : S_stone;   break;
  1091.     case VWALL:    idx = ptr->seen ? S_vwall  : S_stone;   break;
  1092.     case TLCORNER:    idx = ptr->seen ? S_tlcorn : S_stone;    break;
  1093.     case TRCORNER:    idx = ptr->seen ? S_trcorn : S_stone;    break;
  1094.     case BLCORNER:    idx = ptr->seen ? S_blcorn : S_stone;    break;
  1095.     case BRCORNER:    idx = ptr->seen ? S_brcorn : S_stone;    break;
  1096.     case CROSSWALL:    idx = ptr->seen ? S_crwall : S_stone;    break;
  1097.     case TUWALL:    idx = ptr->seen ? S_tuwall : S_stone;    break;
  1098.     case TDWALL:    idx = ptr->seen ? S_tdwall : S_stone;    break;
  1099.     case TLWALL:    idx = ptr->seen ? S_tlwall : S_stone;    break;
  1100.     case TRWALL:    idx = ptr->seen ? S_trwall : S_stone;    break;
  1101.     case SDOOR:
  1102.         if (ptr->seen)
  1103.         idx = (ptr->horizontal) ? S_hwall : S_vwall;
  1104.         else
  1105.         idx = S_stone;
  1106.         break;
  1107.     case DOOR:
  1108.         if (ptr->doormask) {
  1109.         if (ptr->doormask & D_BROKEN)
  1110.             idx = S_ndoor;
  1111.         else if (ptr->doormask & D_ISOPEN)
  1112.             idx = (ptr->horizontal) ? S_hodoor : S_vodoor;
  1113.         else            /* else is closed */
  1114.             idx = (ptr->horizontal) ? S_hcdoor : S_vcdoor;
  1115.         } else
  1116.         idx = S_ndoor;
  1117.         break;
  1118.     case POOL:
  1119.     case MOAT:        idx = S_pool;      break;
  1120.     case STAIRS:
  1121.         idx = (ptr->ladder & LA_DOWN) ? S_dnstair : S_upstair;
  1122.         break;
  1123.     case LADDER:
  1124.         idx = (ptr->ladder & LA_DOWN) ? S_dnladder : S_upladder;
  1125.         break;
  1126.     case FOUNTAIN:        idx = S_fountain; break;
  1127.     case SINK:        idx = S_sink;     break;
  1128.     case ALTAR:        idx = S_altar;    break;
  1129.     case THRONE:        idx = S_throne;   break;
  1130.     case LAVAPOOL:        idx = S_lava;      break;
  1131.     case ICE:        idx = S_ice;      break;
  1132.     case AIR:        idx = S_air;      break;
  1133.     case CLOUD:        idx = S_cloud;      break;
  1134.     case WATER:        idx = S_water;      break;
  1135.     case DBWALL:
  1136.         idx = (ptr->horizontal) ? S_hcdbridge : S_vcdbridge;
  1137.         break;
  1138.     case DRAWBRIDGE_UP:
  1139.         switch(ptr->drawbridgemask & DB_UNDER) {
  1140.         case DB_MOAT:  idx = S_pool; break;
  1141.         case DB_LAVA:  idx = S_lava; break;
  1142.         case DB_ICE:   idx = S_ice;  break;
  1143.         case DB_FLOOR: idx = S_room; break;
  1144.         default:
  1145.         impossible("Strange db-under: %d",
  1146.                ptr->drawbridgemask & DB_UNDER);
  1147.         idx = S_room; /* something is better than nothing */
  1148.         break;
  1149.         }
  1150.         break;
  1151.     case DRAWBRIDGE_DOWN:
  1152.         idx = (ptr->horizontal) ? S_hodbridge : S_vodbridge;
  1153.         break;
  1154.     default:
  1155.         impossible("back_to_glyph:  unknown level type [ = %d ]",ptr->typ);
  1156.         idx = S_room;
  1157.         break;
  1158.     }
  1159.  
  1160.     return cmap_to_glyph(idx);
  1161. }
  1162.  
  1163.  
  1164. /*
  1165.  * swallow_to_glyph()
  1166.  *
  1167.  * Convert a monster number and a swallow location into the correct glyph.
  1168.  * If you don't want a patchwork monster while hallucinating, decide on
  1169.  * a random monster in swallowed() and don't use what_mon() here.
  1170.  */
  1171. static int
  1172. swallow_to_glyph(mnum, loc)
  1173.     int mnum;
  1174.     int loc;
  1175. {
  1176.     if (loc < S_sw_tl || S_sw_br < loc) {
  1177.     impossible("swallow_to_glyph: bad swallow location");
  1178.     loc = S_sw_br;
  1179.     }
  1180.     return ((int) (what_mon(mnum)<<3) | (loc - S_sw_tl)) + GLYPH_SWALLOW_OFF;
  1181. }
  1182.  
  1183.  
  1184.  
  1185. /*
  1186.  * zapdir_to_glyph()
  1187.  *
  1188.  * Change the given zap direction and beam type into a glyph.  Each beam
  1189.  * type has four glyphs, one for each of the symbols below.  The order of
  1190.  * the zap symbols [0-3] as defined in rm.h are:
  1191.  *
  1192.  *    |  S_vbeam    ( 0, 1) or ( 0,-1)
  1193.  *    -  S_hbeam    ( 1, 0) or (-1,    0)
  1194.  *    \  S_lslant    ( 1, 1) or (-1,-1)
  1195.  *    /  S_rslant    (-1, 1) or ( 1,-1)
  1196.  */
  1197. int
  1198. zapdir_to_glyph(dx, dy, beam_type)
  1199.     register int dx, dy;
  1200.     int beam_type;
  1201. {
  1202.     if (beam_type >= NUM_ZAP) {
  1203.     impossible("zapdir_to_glyph:  illegal beam type");
  1204.     beam_type = 0;
  1205.     }
  1206.     dx = (dx == dy) ? 2 : (dx && dy) ? 3 : dx ? 1 : 0;
  1207.  
  1208.     return ((int) ((beam_type << 2) | dx)) + GLYPH_ZAP_OFF;
  1209. }
  1210.  
  1211.  
  1212. /*
  1213.  * Utility routine for dowhatis() used to find out the glyph displayed at
  1214.  * the location.  This isn't necessarily the same as the glyph in the levl
  1215.  * structure, so we must check the "third screen".
  1216.  */
  1217. int
  1218. glyph_at(x, y)
  1219.     xchar x,y;
  1220. {
  1221.     if(x < 0 || y < 0 || x >= COLNO || y >= ROWNO)
  1222.     return cmap_to_glyph(S_room);            /* XXX */
  1223.     return gbuf[y][x].glyph;
  1224. }
  1225.  
  1226. /*display.c*/
  1227.